package com.jl.js.console;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.ui.console.IOConsole;
import org.eclipse.ui.console.IOConsoleOutputStream;
import org.eclipse.wb.swt.SWTResourceManager;

import com.jl.card.JL;
import com.jl.js.filepath.FilePathUtil;

public class ConsoleLogger {

	private IOConsole console;
	private IOConsoleOutputStream debugStream;
	private IOConsoleOutputStream infoStream;
	private IOConsoleOutputStream errorStream;
	private IOConsoleOutputStream warnStream;

	private int level = JL.LOG_LEVEL_ALL;

	private List<String> list = new ArrayList<String>();

	private ConsoleLogger(IOConsole console) {
		this.console = console;
		debugStream = console.newOutputStream();
		debugStream.setColor(SWTResourceManager.getColor(8, 67, 131));
		debugStream.setFontStyle(SWT.BOLD);

		infoStream = console.newOutputStream();
		infoStream.setColor(SWTResourceManager.getColor(140,45,141));

		errorStream = console.newOutputStream();
		errorStream.setColor(SWTResourceManager.getColor(255, 0, 0));

		warnStream = console.newOutputStream();
		warnStream.setColor(SWTResourceManager.getColor(255, 128, 0));

	}

	public static ConsoleLogger getInstance(IOConsole name) {
		return new ConsoleLogger(name);
	}

	public String getName() {
		return console.getName();
	}

	public void debug(String format, Object... args) {
		if (level == JL.LOG_LEVEL_ALL || level == JL.LOG_LEVEL_DEBUG_ONLY)
			try {
				String str = "#DEBUG# " + new Formatter().format(format, args);
				list.add(str);
				debugStream.write(str + '\n');
			} catch (IOException e) {
				e.printStackTrace();
			}
	}

	public void info(String format, Object... args) {
		if (level == JL.LOG_LEVEL_ALL || level == JL.LOG_LEVEL_INFO)
			try {
				String str = "#INFO# " + new Formatter().format(format, args);
				list.add(str);
				infoStream.write(str + '\n');
			} catch (IOException e) {
				e.printStackTrace();
			}
	}

	public void error(String format, Object... args) {
		if (level != JL.LOG_LEVEL_DEBUG_ONLY && level != JL.LOG_LEVEL_NOLOG)
			try {
				String str = "#ERROR# " + new Formatter().format(format, args);
				list.add(str);
				errorStream.write(str + '\n');
			} catch (IOException e) {
				e.printStackTrace();
			}
	}

	public void warn(String format, Object... args) {
		if (level == JL.LOG_LEVEL_ALL || level == JL.LOG_LEVEL_INFO
				|| level == JL.LOG_LEVEL_WARN)

			try {
				String str = "#WARN# " + new Formatter().format(format, args);
				list.add(str);
				warnStream.write(str + '\n');
			} catch (IOException e) {
				e.printStackTrace();
			}
	}

	public void setLevel(int level) {
		this.level = level;
	}

	public void save(String name) throws IOException {
		File file = FilePathUtil.getJSFilePath(name).getFile();
		System.out.println(file.getAbsolutePath());
		
		if (!file.exists()) {
			file.createNewFile();
		}
		PrintWriter p = new PrintWriter(file);
		for (String s : list) {
			p.println(s);
		}
		p.close();
	}

	/**
	 * for tracer input
	 * 
	 * @param message
	 */
	protected void tracer(String message) {
		list.add(message);
	}

	protected void tracer(String format, Object... args) {
		String str = new Formatter().format(format, args);
		list.add(str);
	}

	class Formatter {

		private char left = '{';
		private char right = '}';

		private int cur_begin;
		private int cur_end;

		public Formatter() {
		}

		public String format(String format, Object... args) {
			for (Object obj : args) {
				format = formatOne(format, obj);
			}
			return format;
		}

		private String formatOne(String format, Object arg) {
			String f = getFirstInnerString(format);
			if (f.equals("")) {
				return repleaceFirst(format, arg.toString());
			}
			if (arg instanceof Double) {
				boolean isContain = false;
				for (char ch : f.toCharArray()) {
					if (ch == 'x' || ch == 'X' || ch == 'o' || ch == 'd') {
						isContain = true;
						break;
					}
				}
				if (isContain) {
					Double d = (Double) arg;
					Long i = new Long(d.longValue());
					arg = i;
				}
			}
			f = "%" + f;
			String inner = String.format(f, arg);
			return repleaceFirst(format, inner);
		}

		private String repleaceFirst(String format, String string) {
			int len = cur_end - cur_begin - 1;
			return format.replaceFirst("\\{.{" + len + "}\\}", string);
		}

		private String getFirstInnerString(String str) {
			cur_begin = str.indexOf(left);
			cur_end = str.indexOf(right);
			return str.substring(cur_begin + 1, cur_end);
		}

	}
}
